﻿using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using FacebookWrapper;
using FacebookWrapper.ObjectModel;
using Ex3.Logic;
using Ex3.Repository;
using Ex3.FriendSelector;

namespace Ex3
{
    public partial class MainForm : Form
    {
        private readonly LoginForm m_LoginForm;
        private User m_LoggedInUser;
        public CirclesOfFriendsClient m_CirclesOfFriends;
        private RankPhotos m_RankedPhotos;
        private ComposerForm m_ComposerCircleForm;
        private Selector m_Selector;
        
        public MainForm()
        {
            this.InitializeComponent();
            this.m_LoginForm = new LoginForm();
            this.m_RankedPhotos = new RankPhotos();
        }

        private void AttachComposerForm()
        {
            this.m_ComposerCircleForm = new ComposerForm(this.m_LoggedInUser);
            this.m_ComposerCircleForm.AttachObserver(new CreatedCircleDelegate(this.AddNewCircle));
            this.m_ComposerCircleForm.ShowDialog();
        }

        private void showSettingsAndStartApp()
        {
            this.Show();
            this.m_LoginForm.ShowDialog();
            if (this.m_LoginForm.m_LoggedInUser == null)
            {
                this.Close();
            }
            else
            {
                this.fetchUserInfo();
            }
        }

        private void fetchUserInfo()
        {
            this.m_LoggedInUser = this.m_LoginForm.m_LoggedInUser;
            this.Text = this.m_LoggedInUser.Name;

            if (this.m_LoggedInUser != null)
            {
                this.pictureBoxMyProfile.LoadAsync(this.m_LoggedInUser.PictureNormalURL);
                this.FetchNewsFeed();
                this.tabControlMain.Visible = true;
                this.fetchSerilezedUsers();
            }

            try
            {
                this.m_RankedPhotos.Load(this.m_LoggedInUser);
                this.updateRankedPhoto();
                this.timerUpdateRankPhoto.Enabled = true;
            }
            catch
            {
                this.m_RankedPhotos = null;
            }

            this.m_Selector = new Selector(new AllStrategy(), this.m_LoggedInUser.Friends.ToList<User>());
        }

        private void fetchSerilezedUsers()
        {
            this.m_CirclesOfFriends = new CirclesOfFriendsClient();
            this.m_CirclesOfFriends.Load(this.m_LoggedInUser);
            this.inisilizeComboBoxTypes();
        }

        private void inisilizeComboBoxTypes()
        {
            if (this.m_CirclesOfFriends.m_Circles.Count > 0)
            {
                foreach (Circle circle in this.m_CirclesOfFriends.m_Circles)
                {
                    this.comboBoxCircuitType.Items.Add(circle.Name);
                }
            }
        }

        private void loadSerilezedUsers()
        {
            this.m_CirclesOfFriends = new CirclesOfFriendsClient();
            this.m_CirclesOfFriends.Save(this.m_LoggedInUser);
        }

        private void FetchNewsFeed()
        {
            foreach (Post post in this.m_LoggedInUser.NewsFeed)
            {
                if (post.Message != null)
                {
                    this.listBoxNews.Items.Add(post.CreatedTime + ":" + post.From.Name + " - " + post.Message);
                }
                else if (post.Caption != null)
                {
                    this.listBoxNews.Items.Add(post.CreatedTime + ":" + post.From.Name + " - " + post.Caption);
                }
                else
                {
                    this.listBoxNews.Items.Add(post.CreatedTime + ":" + post.From.Name + " - " +
                                               string.Format("[{0}]", post.Type));
                }
            }
        }

        private void splitContainer1_Panel2_Enter(object sender, EventArgs e)
        {
            if (this.listBoxFriends.Items.Count == 0)
            {
                this.m_Selector = new Selector(new AllStrategy(), this.m_LoggedInUser.Friends.ToList<User>());
                this.loadFriendsToList();
            }
        }

        private void loadFriendsToList()
        {
            this.listBoxFriends.Items.Clear();
            this.listBoxFriends.DisplayMember = "Name";

            foreach (User friend in this.m_Selector.GetFriends())
            {
                this.listBoxFriends.Items.Add(friend);
            }
        }

        private void tabControlMain_Selected(object sender, TabControlEventArgs e)
        {
            if (this.listBoxFriends.Items.Count == 0)
            {
                this.loadFriendsToList();
            }
        }

        private void listBoxFriends_Click(object sender, EventArgs e)
        {
            User currentItem = (User)this.listBoxFriends.SelectedItem;
            if (currentItem != null)
            {
                this.loadFriendData(currentItem);    
            }

            this.splitContainer1.Panel2.Show();
        }

        private void loadFriendsStatuses(User i_Friend)
        {
            this.listBoxStatuses.DisplayMember = "Message";

            this.listBoxStatuses.Items.Clear();

            for (int numberOfStatus = 0; numberOfStatus < 5; ++numberOfStatus)
            {
                if (i_Friend.Statuses.Count > numberOfStatus)
                {
                    Status currentStatus = i_Friend.Statuses[numberOfStatus];
                    this.listBoxStatuses.Items.Add(currentStatus.UpdateTime.Value.ToString() + " " + currentStatus);
                }
            }
        }

        private void loadFriendsCheckins(User i_Friend)
        {
            const int NUMBER_OF_CHECKINS = 5;
            this.listBoxCheckins.DisplayMember = "Message";

            this.listBoxCheckins.Items.Clear();

            for (int numberOfCheckins = 0; numberOfCheckins < NUMBER_OF_CHECKINS; ++numberOfCheckins)
            {
                if (i_Friend.Checkins.Count > numberOfCheckins)
                {
                    Checkin currentCheckin = i_Friend.Checkins[numberOfCheckins];
                    this.listBoxCheckins.Items.Add(currentCheckin.CreatedTime.Value.ToString() + " " +
                                                   currentCheckin.Message);
                }
            }
        }

        private void loadFriendData(User i_Friend)
        {
            this.labelName.Text = i_Friend.Name;
            this.labelName.Visible = true;
            this.pictureBoxFriend.LoadAsync(i_Friend.PictureNormalURL);
            this.loadFriendsStatuses(i_Friend);
            this.loadFriendsCheckins(i_Friend);
        }

        private void textBoxSearchFriends_TextChanged(object sender, EventArgs e)
        {
            if (this.textBoxSearchFriends.Text == string.Empty)
            {
                this.buttonSearchFriends.Enabled = false;
            }
            else
            {
                Common.FindInListBox(this.listBoxFriends, this.textBoxSearchFriends);
                this.buttonSearchFriends.Enabled = true;
            }
        }

        private void buttonSearchFriends_Click(object sender, EventArgs e)
        {
            if (this.textBoxSearchFriends.Text != string.Empty)
            {
                User userFriend = Logic.FriendsQuery.GetFriendsByName(
                    this.textBoxSearchFriends.Text, this.m_LoginForm.m_LoggedInUser);

                // friend not found
                if (userFriend != null)
                {
                    this.loadFriendData(userFriend);
                }
                else
                {
                    MessageBox.Show("Sorry, could not find your friend.", "Friend not found");
                    this.textBoxSearchFriends.Text = string.Empty;
                }
            }
        }

        private void buttonSearchPoto_Click(object sender, EventArgs e)
        {
            this.openFileDialogPhoto.ShowDialog();

            // Check if a photo was selected
            if (this.openFileDialogPhoto.FileName != string.Empty)
            {
                this.textBoxChosenPhoto.Text = this.openFileDialogPhoto.SafeFileName;
                this.pictureBoxUpload.LoadAsync(this.openFileDialogPhoto.FileName);
            }
        }

        private void textBoxChosenPhoto_TextChanged(object sender, EventArgs e)
        {
            if (this.textBoxChosenPhoto.Text != string.Empty)
            {
                this.buttonPost.Enabled = true;
                this.pictureBoxUpload.Visible = true;
            }
            else
            {
                this.buttonPost.Enabled = false;
            }
        }

        private void buttonPost_Click(object sender, EventArgs e)
        {
            this.m_LoginForm.m_LoggedInUser.PostPhoto(this.openFileDialogPhoto.FileName, this.textBoxPhotoDescription.Text, null, null); 
            MessageBox.Show("Photo posted successfully!", "Post photo");
            this.textBoxPhotoDescription.Text = string.Empty;
            this.textBoxChosenPhoto.Text = string.Empty;
            this.pictureBoxUpload.Visible = false;
        }

        private void textBoxStatus_TextChanged(object sender, EventArgs e)
        {
            if (this.textBoxStatus.Text != string.Empty)
            {
                this.buttonPostStatus.Enabled = true;
            }
            else
            {
                this.buttonPostStatus.Enabled = false;
            }
        }

        private void buttonPostStatus_Click(object sender, EventArgs e)
        {
            this.m_LoginForm.m_LoggedInUser.PostStatus(this.textBoxStatus.Text, null);
            MessageBox.Show("Status posted successfully!", "Post status");
            this.textBoxStatus.Text = string.Empty;
        }

        private void buttonRankPhotos_Click(object sender, EventArgs e)
        {
            RankPhotosForm RankForm;

            if (this.m_RankedPhotos != null)
            {
                RankForm = new RankPhotosForm(this.m_LoggedInUser, this.m_RankedPhotos);
            }
            else
            {
                RankForm = new RankPhotosForm(this.m_LoggedInUser);
            }

            DialogResult result = RankForm.ShowDialog();

            if (result == System.Windows.Forms.DialogResult.Cancel)
            {
                this.m_RankedPhotos = RankForm.ReturnPhotos;

                this.updateRankedPhoto();
            }
        }

        private RankedPhoto chooseRandomPhoto()
        {
            RankedPhoto randomPhoto = null;

            if (this.m_RankedPhotos != null)
            {
                List<string> keys = new List<string>();

                foreach (RankedPhoto currentPhoto in this.m_RankedPhotos)
                {
                    if ((int)currentPhoto.RankedStars >= (int)this.numericUpDownPhotosSelect.Value)
                    {
                        keys.Add(currentPhoto.ID);
                    }
                }

                Random random = new Random();
                int randomKey = random.Next(0, keys.Count);

                string selectedKey = keys[randomKey];

                randomPhoto = this.m_RankedPhotos.GetPhotoByID(selectedKey);
            }

            return randomPhoto;
        }

        private void updateRankedPhoto()
        {
            RankedPhoto photo = this.chooseRandomPhoto();

            if (photo != null)
            {
                this.pictureBoxRank.LoadAsync(photo.URL);
            }
        }

        private void timerUpdateRankPhoto_Tick(object sender, EventArgs e)
        {
            this.updateRankedPhoto();
        }

        private void buttonAddToCircle_Click(object sender, EventArgs e)
        {
            this.dienableButtensInCricuitPage();

            this.displayFrindsInListBox();
            this.listBoxListFrindsAddToCircle.Visible = true;
            this.TextBoxSearch.Visible = true;
            this.labelChooseCircle.Visible = true;
            this.buttonAdd.Visible = true;
            this.comboBoxCircuitType.Visible = true;

            this.comboBoxCircuitType.SelectedIndexChanged += this.comboBoxCircuitTypeForAdd_SelectedIndexChanged;
            this.comboBoxCircuitType.SelectedIndexChanged -= this.comboBoxCircuitTypeForShow_SelectedIndexChanged;  
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            Common.FindInListBox(this.listBoxListFrindsAddToCircle, this.TextBoxSearch);
        }

        private void buttonAdd_Click(object sender, EventArgs e)
        {
            this.addFriendToCircle();
        }

        private void comboBoxCircuitTypeForAdd_SelectedIndexChanged(object sender, EventArgs e)
        {
            bool IsItShow = false;
            this.checkIfButtonCanBeEnabled(IsItShow);
        }

        private void comboBoxCircuitTypeForShow_SelectedIndexChanged(object sender, EventArgs e)
        {
            bool IsItShow = true;
            this.checkIfButtonCanBeEnabled(IsItShow);
        }

        private void checkIfButtonCanBeEnabled(bool i_IsItShow)
        {
            if (this.comboBoxCircuitType.SelectedItem != null && this.TextBoxSearch.Text != null)
            {
                if (this.buttonAdd.Visible == true)
                {
                    this.buttonAdd.Enabled = true;
                }
                else
                {
                    this.buttonDelete.Enabled = true;
                }
            }
            else
            {
                this.buttonDelete.Enabled = false;
                this.buttonAdd.Enabled = false;
            }
        }

        private void listBoxListFrindsAddToGroup_SelectedIndexChanged(object sender, EventArgs e)
        {
            bool IsItShow = false;
            if (this.listBoxListFrindsAddToCircle.SelectedItem != null)
            {
                this.TextBoxSearch.Text = ((User)this.listBoxListFrindsAddToCircle.SelectedItem).Name;
            }

            this.checkIfButtonCanBeEnabled(IsItShow);
        }

        private void displayFrindsInListBox()
        {
            this.listBoxListFrindsAddToCircle.Items.Clear();
            this.listBoxListFrindsAddToCircle.DisplayMember = "Name";
            foreach (User friend in this.m_LoggedInUser.Friends)
            {
                this.listBoxListFrindsAddToCircle.Items.Add(friend);
            }
        }

        private void displayFrindsInListBox(string i_TypeCircle)
        {
            this.listBoxListFrindsAddToCircle.Items.Clear();
            this.listBoxListFrindsAddToCircle.DisplayMember = "Name";

            Circle circle = this.m_CirclesOfFriends.GetCircleByType(i_TypeCircle);
            if (circle.FriendsInCircle.Count > 0)
            {
                foreach (SerializableUserInCircuit friend in circle.FriendsInCircle)
                {
                    User tempUser = FriendsQuery.GetFriendsByName(friend.Name, this.m_LoggedInUser);
                    this.listBoxListFrindsAddToCircle.Items.Add(tempUser);
                    this.timerUpdatePhotosCircle.Enabled = true;
                    this.pictureBoxProfileCircle.Visible = true;
                    this.listBoxListFrindsAddToCircle.Visible = true;
                    this.TextBoxSearch.Visible = true;
                    this.buttonDelete.Visible = true;
                    this.timerUpdatePhotosCircle.Start();
                }
            }
            else
            {
                MessageBox.Show("Circle is empty");
            }
        }

        private void dienableButtensInCricuitPage()
        {
            this.clearDataFromListBoxCircuit();
            this.pictureBoxProfileCircle.Visible = false;
            this.labelChooseCircle.Visible = false;
            this.buttonDelete.Visible = false;
            this.buttonDelete.Enabled = false;
            this.buttonAdd.Visible = false;
            this.comboBoxCircuitType.Visible = false;
            this.TextBoxSearch.Visible = false;
            this.listBoxListFrindsAddToCircle.Visible = false;
            this.buttonCopyCircle.Visible = false;
        }

        private void buttonDeleteAFriendFromList_Click(object sender, EventArgs e)
        {
            this.deleteFriendFromCircle();
        }

        private void buttonDeleteATypeOfCircle_Click(object sender, EventArgs e)
        {
            this.deleteTypeOfCircle();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            this.showSettingsAndStartApp();
        }

        private void buttonShowCircle_Click(object sender, EventArgs e)
        {
            this.dienableButtensInCricuitPage();
            this.comboBoxCircuitType.Visible = true;
            this.labelChooseCircle.Visible = true;

            this.buttonDelete.Click -= this.buttonDeleteATypeOfCircle_Click;
            this.buttonDelete.Click -= this.buttonDeleteAFriendFromList_Click;
            this.buttonDelete.Click += this.buttonDeleteAFriendFromList_Click;

            this.comboBoxCircuitType.SelectedIndexChanged -= this.comboBoxCircuitTypeForAdd_SelectedIndexChanged;
            this.comboBoxCircuitType.SelectedIndexChanged += this.comboBoxCircuitTypeForShow_SelectedIndexChanged;
        }

        private void clearDataFromListBoxCircuit()
        {
            this.TextBoxSearch.Text = string.Empty;
        }

        private void updateListBoxView()
        {
            this.TextBoxSearch.Text = string.Empty;
            this.ShowCircle();
        }

        private void buttonShow_Click(object sender, EventArgs e)
        {
            this.ShowCircle();
        }

        private void chooseRandomProfilePhotoForCircles(string i_TypeCircle)
        {
            Circle circle = this.m_CirclesOfFriends.GetCircleByType(i_TypeCircle);

            if ((circle != null) && (circle.FriendsInCircle.Count > 0))
            {
                this.pictureBoxProfileCircle.LoadAsync(this.m_CirclesOfFriends.ChooseRandomProfilePhoto(circle));
            }
        }

        private void timerUpdatePhotosCircle_Tick(object sender, EventArgs e)
        {
            this.chooseRandomProfilePhotoForCircles(this.m_CirclesOfFriends.TypeCircleShown);
        }

        private void buttonAddNewCircleType_Click(object sender, EventArgs e)
        {
            this.dienableButtensInCricuitPage();
            this.AttachComposerForm();
        }

        private void listBoxListFrindsAddToCircle_DoubleClick(object sender, EventArgs e)
        {
            User currentFriend = (User)this.listBoxListFrindsAddToCircle.SelectedItem;
            
            if (currentFriend != null)
            {
                this.loadFriendData(currentFriend);
                
                this.tabControlMain.SelectedTab = this.tabControlMain.TabPages[1];
                this.tabPageFriends.Show();
                this.listBoxFriends.SelectedItem = currentFriend;
            }
        }

        private void deleteFriendFromCircle()
        {
            string nameOfFriend = this.TextBoxSearch.Text;
            string nameOfCircuit = string.Empty;
            if (this.comboBoxCircuitType.SelectedItem != null)
            {
                nameOfCircuit = this.comboBoxCircuitType.SelectedItem.ToString();
            }

            if (nameOfFriend != string.Empty && nameOfCircuit != string.Empty)
            {
                Circle circle = this.m_CirclesOfFriends.GetCircleByType(nameOfCircuit);
                this.m_CirclesOfFriends.DeleteFriendFromCircuit(nameOfFriend, circle);

                this.m_CirclesOfFriends.Save(this.m_LoggedInUser);
                this.updateListBoxView();
                MessageBox.Show("Friend Deleted!");
            }
            else
            {
                MessageBox.Show("You need to choose a friend to delete", "Friend not selected");
            }
        }

        private void addFriendToCircle()
        {
            string nameOfFriend = this.TextBoxSearch.Text;
            string nameOfCircuit = (string)this.comboBoxCircuitType.SelectedItem;
            if (nameOfFriend != string.Empty)
            {
                User friend = FriendsQuery.GetFriendsByName(nameOfFriend, this.m_LoginForm.m_LoggedInUser);
                Circle circle = this.m_CirclesOfFriends.GetCircleByType(nameOfCircuit);

                if (circle.ContainsFriend(friend.Id))
                {
                    MessageBox.Show("Friend already exists in the group", "Friend exists");
                }
                else
                {
                    this.m_CirclesOfFriends.AddFriendToCircle(friend, circle);

                    this.clearDataFromListBoxCircuit();
                    this.m_CirclesOfFriends.Save(this.m_LoggedInUser);

                    MessageBox.Show("Friend has been added successfully", "Friend added");
                    this.ShowCircle();
                }
            }
            else
            {
                MessageBox.Show("You did not select a friend.", "Friend not selected");
            }
        }

        private void deleteTypeOfCircle()
        {
            string typeOfCircle = this.comboBoxCircuitType.Text;
            if (typeOfCircle != string.Empty)
            {
                this.comboBoxCircuitType.Items.Remove(typeOfCircle);
                this.comboBoxCircuitType.Refresh();
                this.m_CirclesOfFriends.DeleteCircle(this.m_CirclesOfFriends.m_Circles, this.m_CirclesOfFriends.GetCircleByType(typeOfCircle));
             
                this.dienableButtensInCricuitPage();
                this.m_CirclesOfFriends.Save(this.m_LoggedInUser);
                MessageBox.Show("Type Deleted!");
            }
            else
            {
                MessageBox.Show("Choose a circle", "Circle not chosen");
            }
        }

        private void ShowCircle()
        {
            if (this.comboBoxCircuitType.SelectedItem != null)
            {
                this.m_CirclesOfFriends.TypeCircleShown = (string) this.comboBoxCircuitType.SelectedItem;
                this.chooseRandomProfilePhotoForCircles(this.m_CirclesOfFriends.TypeCircleShown);
                this.displayFrindsInListBox(this.m_CirclesOfFriends.TypeCircleShown);
                this.buttonCopyCircle.Visible = true;
                this.buttonAdd.Visible = false;
                this.TextBoxSearch.Text = string.Empty;
            }
        }

        /// <summary>
        /// report from composer form of a new circle that added 
        /// </summary>
        /// <param name="i_Circle"></param>
        private void AddNewCircle(Circle i_Circle )
        {
            this.m_CirclesOfFriends.addNewCircle(i_Circle);
            this.comboBoxCircuitType.Items.Add(i_Circle.Name);
            this.comboBoxCircuitType.Refresh();
            this.m_CirclesOfFriends.Save(this.m_LoggedInUser);

            MessageBox.Show("Circle was created successfully.", "Circle created");
        }

        private void buttonDeleteCircle_Click(object sender, EventArgs e)
        {
            this.dienableButtensInCricuitPage();
            this.comboBoxCircuitType.Visible = true;
            this.buttonDelete.Visible = true;
            this.buttonDelete.Enabled = true;

            this.buttonDelete.Click -= this.buttonDeleteAFriendFromList_Click;
            this.buttonDelete.Click -= this.buttonDeleteATypeOfCircle_Click;
            this.buttonDelete.Click += this.buttonDeleteATypeOfCircle_Click;
        }

        private void buttonCopyCircle_Click(object sender, EventArgs e)
        {
            this.panelCopyCircle.Visible = true;
        }

        private void buttonSaveCopyCircle_Click(object sender, EventArgs e)
        {
            Circle clonedCircle = 
                this.m_CirclesOfFriends.GetCircleByType(this.m_CirclesOfFriends.TypeCircleShown).DeepClone();
            if (this.textBoxCopyCircleNewName.Text == string.Empty)
            {
                MessageBox.Show("Enter a name to the new circle", "Missing circle name"); 
            }
            else if (this.comboBoxCircuitType.FindStringExact(this.textBoxCopyCircleNewName.Text) > 0)
            {
                MessageBox.Show("Enter a different name to the new circle", "Circle name already exists"); 
            }
            else
            {
                clonedCircle.Name = this.textBoxCopyCircleNewName.Text;
                this.AddNewCircle(clonedCircle);
                this.textBoxCopyCircleNewName.Text = string.Empty;
                this.panelCopyCircle.Visible = false;
                this.buttonCopyCircle.Visible = false;
                this.comboBoxCircuitType.SelectedItem = clonedCircle.Name;
                this.ShowCircle();
            }
        }

        private void comboBoxCircuitType_SelectionChangeCommitted(object sender, EventArgs e)
        {
            this.ShowCircle();
        }

        private void buttonSpecialSearcher_Click(object sender, EventArgs e)
        {
            FriendsSelectorForm selector = new FriendsSelectorForm(this.m_LoginForm.m_LoggedInUser.Friends.ToList<User>());
            selector.ShowDialog();
            if (selector.Strategy != null)
            {
                this.m_Selector.SetStrategy(selector.Strategy);
                this.loadFriendsToList();
                this.buttonShowAllFriends.Enabled = true;
            }
        }

        private void buttonShowAllFriends_Click(object sender, EventArgs e)
        {
            this.m_Selector.SetStrategy(new AllStrategy());
            this.loadFriendsToList();
            this.buttonShowAllFriends.Enabled = false;
        }
    }
}